{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "0GTyDZmDVBml"
   },
   "source": [
    "# HyperStyle Inference Notebook"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "1rvG7nRoGDUY"
   },
   "source": [
    "## Prepare Environment and Download HyperStyle Code"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "QRzve9Y5DucV",
    "outputId": "960d210c-07ce-4435-b6c6-6472ef78befb"
   },
   "outputs": [],
   "source": [
    "#@title Clone HyperStyle Repo and Install Ninja { display-mode: \"form\" } \n",
    "import os\n",
    "os.chdir('/content')\n",
    "CODE_DIR = 'hyperstyle'\n",
    "\n",
    "## clone repo\n",
    "!git clone https://github.com/yuval-alaluf/hyperstyle.git $CODE_DIR\n",
    "\n",
    "## install ninja\n",
    "!wget https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-linux.zip\n",
    "!sudo unzip ninja-linux.zip -d /usr/local/bin/\n",
    "!sudo update-alternatives --install /usr/bin/ninja ninja /usr/local/bin/ninja 1 --force\n",
    "\n",
    "os.chdir(f'./{CODE_DIR}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "DxeMz-doE_pr"
   },
   "outputs": [],
   "source": [
    "#@title Import Packages { display-mode: \"form\" } \n",
    "import time\n",
    "import sys\n",
    "import pprint\n",
    "from tqdm import tqdm\n",
    "import numpy as np\n",
    "from PIL import Image\n",
    "import torch\n",
    "import torchvision.transforms as transforms\n",
    "\n",
    "import imageio\n",
    "from IPython.display import HTML\n",
    "from base64 import b64encode\n",
    "\n",
    "sys.path.append(\".\")\n",
    "sys.path.append(\"..\")\n",
    "\n",
    "from notebooks.notebook_utils import Downloader, HYPERSTYLE_PATHS, W_ENCODERS_PATHS, run_alignment\n",
    "from utils.common import tensor2im\n",
    "from utils.inference_utils import run_inversion\n",
    "from utils.domain_adaptation_utils import run_domain_adaptation\n",
    "from utils.model_utils import load_model, load_generator\n",
    "\n",
    "%load_ext autoreload\n",
    "%autoreload 2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "gKGnZ8DmICRU"
   },
   "source": [
    "## Define Download Configuration\n",
    "Select below whether you wish to download all models using `pydrive`. Note that if you do not use `pydrive`, you may encounter a \"quota exceeded\" error from Google Drive."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "QQ6XEmlHlXbk"
   },
   "outputs": [],
   "source": [
    "#@title { display-mode: \"form\" } \n",
    "download_with_pydrive = True #@param {type:\"boolean\"} \n",
    "downloader = Downloader(code_dir=CODE_DIR, use_pydrive=download_with_pydrive)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "pU0snuo-SUHs"
   },
   "source": [
    "## Select Domain for Inference"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "XESWAO65kTJt"
   },
   "outputs": [],
   "source": [
    "#@title Select which domain you wish to perform inference on: { display-mode: \"form\" } \n",
    "experiment_type = 'faces' #@param ['faces', 'cars', 'afhq_wild']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "9Tozsg81kTKA",
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "## Define Inference Parameters\n",
    "\n",
    "Below we have a dictionary defining parameters such as the path to the pretrained model to use and the path to the image to perform inference on. While we provide default values to run this script, feel free to change as needed."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "pHz3Js0HEXbi",
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "EXPERIMENT_DATA_ARGS = {\n",
    "    \"faces\": {\n",
    "        \"model_path\": \"./pretrained_models/hyperstyle_ffhq.pt\",\n",
    "        \"w_encoder_path\": \"./pretrained_models/faces_w_encoder.pt\",\n",
    "        \"image_path\": \"./notebooks/images/face_image.jpg\",\n",
    "        \"transform\": transforms.Compose([\n",
    "            transforms.Resize((256, 256)),\n",
    "            transforms.ToTensor(),\n",
    "            transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])])\n",
    "    },\n",
    "    \"cars\": {\n",
    "        \"model_path\": \"./pretrained_models/hyperstyle_cars.pt\",\n",
    "        \"w_encoder_path\": \"./pretrained_models/cars_w_encoder.pt\",\n",
    "        \"image_path\": \"./notebooks/images/car_image.jpg\",\n",
    "        \"transform\": transforms.Compose([\n",
    "            transforms.Resize((192, 256)),\n",
    "            transforms.ToTensor(),\n",
    "            transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])])\n",
    "    },\n",
    "    \"afhq_wild\": {\n",
    "        \"model_path\": \"./pretrained_models/hyperstyle_afhq_wild.pt\",\n",
    "        \"w_encoder_path\": \"./pretrained_models/afhq_wild_w_encoder.pt\",\n",
    "        \"image_path\": \"./notebooks/images/afhq_wild_image.jpg\",\n",
    "        \"transform\": transforms.Compose([\n",
    "            transforms.Resize((256, 256)),\n",
    "            transforms.ToTensor(),\n",
    "            transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])])\n",
    "    }\n",
    "}\n",
    "\n",
    "EXPERIMENT_ARGS = EXPERIMENT_DATA_ARGS[experiment_type]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "pmOsCJWB6mGM",
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "## Download Models\n",
    "To reduce the number of requests to fetch the model, we'll check if the model was previously downloaded and saved before downloading the model. We'll download the model for the selected experiment and save it to the folder `hyperstyle/pretrained_models`.\n",
    "\n",
    "We also need to verify that the model was downloaded correctly. All of our models should weigh approximately 1.3GB. Note that if the file weighs several KBs, you most likely encounter a \"quota exceeded\" error from Google Drive."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "jQ31J_m7kTJ8",
    "outputId": "6a67f6f9-564e-4d98-be88-ab44cee23406",
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "#@title Download HyperStyle Model { display-mode: \"form\" } \n",
    "if not os.path.exists(EXPERIMENT_ARGS['model_path']) or os.path.getsize(EXPERIMENT_ARGS['model_path']) < 1000000:\n",
    "    print(f'Downloading HyperStyle model for {experiment_type}...')\n",
    "    downloader.download_file(file_id=HYPERSTYLE_PATHS[experiment_type]['id'], file_name=HYPERSTYLE_PATHS[experiment_type]['name'])\n",
    "    # if google drive receives too many requests, we'll reach the quota limit and be unable to download the model\n",
    "    if os.path.getsize(EXPERIMENT_ARGS['model_path']) < 1000000:\n",
    "        raise ValueError(\"Pretrained model was unable to be downloaded correctly!\")\n",
    "    else:\n",
    "        print('Done.')\n",
    "else:\n",
    "    print(f'HyperStyle model for {experiment_type} already exists!')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "bKeTTMU26mGN",
    "outputId": "a05d6cf1-c04c-4612-e9a5-9a5505ad74a0"
   },
   "outputs": [],
   "source": [
    "#@title Download WEncoder Model { display-mode: \"form\" } \n",
    "if not os.path.exists(EXPERIMENT_ARGS['w_encoder_path']) or os.path.getsize(EXPERIMENT_ARGS['w_encoder_path']) < 1000000:\n",
    "    print(f'Downloading the WEncoder model for {experiment_type}...')\n",
    "    downloader.download_file(file_id=W_ENCODERS_PATHS[experiment_type]['id'], file_name=W_ENCODERS_PATHS[experiment_type]['name'])\n",
    "    # if google drive receives too many requests, we'll reach the quota limit and be unable to download the model\n",
    "    if os.path.getsize(EXPERIMENT_ARGS['w_encoder_path']) < 1000000:\n",
    "        raise ValueError(\"Pretrained model was unable to be downloaded correctly!\")\n",
    "    else:\n",
    "        print('Done.')\n",
    "else:\n",
    "    print(f'WEncoder model for {experiment_type} already exists!')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "TAWrUehTkTKJ",
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "## Load Pretrained Model\n",
    "We assume that you have downloaded all relevant models and placed them in the directory defined by the `EXPERIMENT_DATA_ARGS` dictionary."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 691,
     "referenced_widgets": [
      "046347853a0345d78bb076884bb64a5a",
      "9f0e66dfd1c047ba9d3f56d5eca7bf25",
      "a757876465544169a2b8a6ed70a504b4",
      "d1a0cc1c4f1f4c108650bc83aee3e91a",
      "b116b73b10e54911ac58abbc70aeffe5",
      "d7004b0f0bd640128dffaaf268557d27",
      "293f80be68de46499b2ecfb1eed34bba",
      "3ad88024826049479637996e6cef0f43",
      "a0025637991f4f539ec3d36b8f7800e9",
      "b173bd29966446e6bb3fe67b897ce043",
      "a5bd2327407a465ebfd4d143ec1af0e9"
     ]
    },
    "id": "1t-AOhP1kTKJ",
    "outputId": "117b79c3-f6d6-41eb-e369-fa1d417ae8b6",
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "#@title Load HyperStyle Model { display-mode: \"form\" } \n",
    "model_path = EXPERIMENT_ARGS['model_path']\n",
    "net, opts = load_model(model_path, update_opts={\"w_encoder_checkpoint_path\": EXPERIMENT_ARGS['w_encoder_path']})\n",
    "print('Model successfully loaded!')\n",
    "pprint.pprint(vars(opts))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "mdQ0fXM7ppSr"
   },
   "source": [
    "## Define Utility Functions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "CJbNCfLaplKu"
   },
   "outputs": [],
   "source": [
    "def generate_mp4(out_name, images, kwargs):\n",
    "    writer = imageio.get_writer(out_name + '.mp4', **kwargs)\n",
    "    for image in images:\n",
    "        writer.append_data(image)\n",
    "    writer.close()\n",
    "\n",
    "\n",
    "def get_latent_and_weight_deltas(inputs, net, opts):\n",
    "    opts.resize_outputs = False\n",
    "    opts.n_iters_per_batch = 5\n",
    "    with torch.no_grad():\n",
    "        _, latent, weights_deltas, _ = run_inversion(inputs.to(\"cuda\").float(), net, opts)\n",
    "    weights_deltas = [w[0] if w is not None else None for w in weights_deltas]\n",
    "    return latent, weights_deltas\n",
    "    \n",
    "\n",
    "def get_result_from_vecs(vectors_a, vectors_b, weights_deltas_a, weights_deltas_b, alpha):\n",
    "    results = []\n",
    "    for i in range(len(vectors_a)):\n",
    "        with torch.no_grad():\n",
    "            cur_vec = vectors_b[i] * alpha + vectors_a[i] * (1 - alpha)\n",
    "            cur_weight_deltas = interpolate_weight_deltas(weights_deltas_a, weights_deltas_b, alpha)\n",
    "            res = net.decoder([cur_vec],\n",
    "                              weights_deltas=cur_weight_deltas,\n",
    "                              randomize_noise=False,\n",
    "                              input_is_latent=True)[0]\n",
    "            results.append(res[0])\n",
    "    return results\n",
    "\n",
    "def interpolate_weight_deltas(weights_deltas_a, weights_deltas_b, alpha):\n",
    "    cur_weight_deltas = []\n",
    "    for weight_idx, w in enumerate(weights_deltas_a):\n",
    "        if w is not None:\n",
    "            delta = weights_deltas_b[weight_idx] * alpha + weights_deltas_a[weight_idx] * (1 - alpha)\n",
    "        else:\n",
    "            delta = None\n",
    "        cur_weight_deltas.append(delta)\n",
    "    return cur_weight_deltas\n",
    "    \n",
    "def show_mp4(filename, width):\n",
    "    mp4 = open(filename + '.mp4', 'rb').read()\n",
    "    data_url = \"data:video/mp4;base64,\" + b64encode(mp4).decode()\n",
    "    display(HTML(\"\"\"\n",
    "    <video width=\"%d\" controls autoplay loop>\n",
    "        <source src=\"%s\" type=\"video/mp4\">\n",
    "    </video>\n",
    "    \"\"\" % (width, data_url)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "rCpzl1suFswz"
   },
   "source": [
    "## Define Input Images\n",
    "Define which images to include in the animation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "p6MdqDhDqDhb"
   },
   "outputs": [],
   "source": [
    "SEED = 42\n",
    "np.random.seed(SEED)\n",
    "\n",
    "img_transforms = EXPERIMENT_ARGS['transform']\n",
    "root_dir = \"./notebooks/images/animations\"\n",
    "image_names = ['zuckerberg', 'robbie', 'affleck', 'damon', 'stone', 'jackson', 'pitt', 'watson', 'bezos', 'kunis', 'driver', 'blunt', 'downey', 'johansson', 'dicaprio']\n",
    "image_paths = [os.path.join(root_dir, image) + '.jpg' for image in image_names]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "pvsWbbOytp4a"
   },
   "source": [
    "## Align Images\n",
    "Align the images if needed. You can skip this step if working on non-face images or if your images are pre-aligned."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "MYvyGVgTt2eA"
   },
   "outputs": [],
   "source": [
    "#@title  { display-mode: \"form\" }\n",
    "ALIGN_IMAGES = False #@param {type:\"boolean\"}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "_Bpzbr_Etoow"
   },
   "outputs": [],
   "source": [
    "# only align images if working on faces and if specified\n",
    "if ALIGN_IMAGES and experiment_type == \"faces\":\n",
    "    aligned_image_paths = []\n",
    "    for image_name, image_path in zip(image_names, image_paths): \n",
    "        print(f'Aligning {image_name}...')\n",
    "        aligned_image = run_alignment(image_path)\n",
    "        aligned_path = os.path.join(root_dir, f'{image_name}_aligned.jpg')\n",
    "        # save the aligned image\n",
    "        aligned_image.save(aligned_path)\n",
    "        aligned_image_paths.append(aligned_path)\n",
    "        # use the save aligned images as our input image paths\n",
    "        image_paths = aligned_image_paths"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "nA8pC10Yry6U"
   },
   "source": [
    "## Run Inference!\n",
    "Invert all images and interpolate between the latent codes."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "cellView": "form",
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "CFQyaD1Qqe3d",
    "outputId": "ec98ba28-2944-4932-9a1f-920f9e4929b8"
   },
   "outputs": [],
   "source": [
    "#@title Run Inference! (This may take several minutes)\n",
    "in_images = []\n",
    "all_vecs = []\n",
    "all_weights_deltas = []\n",
    "\n",
    "if experiment_type == \"cars\":\n",
    "    resize_amount = (512, 384)\n",
    "else:\n",
    "    resize_amount = (opts.output_size, opts.output_size)\n",
    "\n",
    "for image_path in image_paths:\n",
    "    print(f'Working on {os.path.basename(image_path)}...')\n",
    "    original_image = Image.open(image_path)\n",
    "    original_image = original_image.convert(\"RGB\")\n",
    "    input_image = img_transforms(original_image)\n",
    "    # get the weight deltas for each image\n",
    "    result_vec, weights_deltas = get_latent_and_weight_deltas(input_image.unsqueeze(0), net, opts)\n",
    "    all_vecs.append([result_vec])\n",
    "    all_weights_deltas.append(weights_deltas)\n",
    "    in_images.append(original_image.resize(resize_amount))\n",
    "\n",
    "n_transition = 25\n",
    "if experiment_type == \"cars\":\n",
    "    SIZE = 384\n",
    "else:\n",
    "    SIZE = opts.output_size\n",
    "\n",
    "images = []\n",
    "image_paths.append(image_paths[0])\n",
    "all_vecs.append(all_vecs[0])\n",
    "all_weights_deltas.append(all_weights_deltas[0])\n",
    "in_images.append(in_images[0])\n",
    "\n",
    "for i in range(1, len(image_paths)):\n",
    "    if i == 0:\n",
    "        alpha_vals = [0] * 10 + np.linspace(0, 1, n_transition).tolist() + [1] * 5\n",
    "    else:\n",
    "        alpha_vals = [0] * 5 + np.linspace(0, 1, n_transition).tolist() + [1] * 5\n",
    "\n",
    "    for alpha in tqdm(alpha_vals):\n",
    "        image_a = np.array(in_images[i - 1])\n",
    "        image_b = np.array(in_images[i])\n",
    "        image_joint = np.zeros_like(image_a)\n",
    "        up_to_row = int((SIZE - 1) * alpha)\n",
    "        if up_to_row > 0:\n",
    "            image_joint[:(up_to_row + 1), :, :] = image_b[((SIZE - 1) - up_to_row):, :, :]\n",
    "        if up_to_row < (SIZE - 1):\n",
    "            image_joint[up_to_row:, :, :] = image_a[:(SIZE - up_to_row), :, :]\n",
    "\n",
    "        result_image = get_result_from_vecs(all_vecs[i - 1], all_vecs[i],\n",
    "                                            all_weights_deltas[i - 1], all_weights_deltas[i],\n",
    "                                            alpha)[0]\n",
    "        if experiment_type == \"cars\":\n",
    "            result_image = result_image[:, 64:448, :]\n",
    "\n",
    "        output_im = tensor2im(result_image)\n",
    "        res = np.concatenate([image_joint, np.array(output_im)], axis=1)\n",
    "        images.append(res)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "wV7yaSXar88q"
   },
   "source": [
    "## Save and Display Result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 533
    },
    "id": "YqvG0oJtsUWt",
    "outputId": "329f7d48-b41b-4ffb-9d8a-2075df99b021"
   },
   "outputs": [],
   "source": [
    "kwargs = {'fps': 15}\n",
    "save_path = \"./notebooks/animations\"\n",
    "os.makedirs(save_path, exist_ok=True)\n",
    "\n",
    "gif_path = os.path.join(save_path, f\"{experiment_type}_gif\")\n",
    "generate_mp4(gif_path, images, kwargs)\n",
    "show_mp4(gif_path, width=opts.output_size)"
   ]
  }
 ],
 "metadata": {
  "accelerator": "GPU",
  "colab": {
   "collapsed_sections": [
    "mdQ0fXM7ppSr"
   ],
   "name": "animations_playground.ipynb",
   "provenance": []
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.3"
  },
  "widgets": {
   "application/vnd.jupyter.widget-state+json": {
    "046347853a0345d78bb076884bb64a5a": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "HBoxModel",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "HBoxModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "HBoxView",
      "box_style": "",
      "children": [
       "IPY_MODEL_a757876465544169a2b8a6ed70a504b4",
       "IPY_MODEL_d1a0cc1c4f1f4c108650bc83aee3e91a",
       "IPY_MODEL_b116b73b10e54911ac58abbc70aeffe5"
      ],
      "layout": "IPY_MODEL_9f0e66dfd1c047ba9d3f56d5eca7bf25"
     }
    },
    "293f80be68de46499b2ecfb1eed34bba": {
     "model_module": "@jupyter-widgets/base",
     "model_module_version": "1.2.0",
     "model_name": "LayoutModel",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "3ad88024826049479637996e6cef0f43": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "ProgressStyleModel",
     "state": {
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "ProgressStyleModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "StyleView",
      "bar_color": null,
      "description_width": ""
     }
    },
    "9f0e66dfd1c047ba9d3f56d5eca7bf25": {
     "model_module": "@jupyter-widgets/base",
     "model_module_version": "1.2.0",
     "model_name": "LayoutModel",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "a0025637991f4f539ec3d36b8f7800e9": {
     "model_module": "@jupyter-widgets/base",
     "model_module_version": "1.2.0",
     "model_name": "LayoutModel",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "a5bd2327407a465ebfd4d143ec1af0e9": {
     "model_module": "@jupyter-widgets/base",
     "model_module_version": "1.2.0",
     "model_name": "LayoutModel",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "a757876465544169a2b8a6ed70a504b4": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "HTMLModel",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "HTMLModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "HTMLView",
      "description": "",
      "description_tooltip": null,
      "layout": "IPY_MODEL_293f80be68de46499b2ecfb1eed34bba",
      "placeholder": "​",
      "style": "IPY_MODEL_d7004b0f0bd640128dffaaf268557d27",
      "value": "100%"
     }
    },
    "b116b73b10e54911ac58abbc70aeffe5": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "HTMLModel",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "HTMLModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "HTMLView",
      "description": "",
      "description_tooltip": null,
      "layout": "IPY_MODEL_a5bd2327407a465ebfd4d143ec1af0e9",
      "placeholder": "​",
      "style": "IPY_MODEL_b173bd29966446e6bb3fe67b897ce043",
      "value": " 83.3M/83.3M [00:06&lt;00:00, 11.1MB/s]"
     }
    },
    "b173bd29966446e6bb3fe67b897ce043": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "DescriptionStyleModel",
     "state": {
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "DescriptionStyleModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "StyleView",
      "description_width": ""
     }
    },
    "d1a0cc1c4f1f4c108650bc83aee3e91a": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "FloatProgressModel",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "FloatProgressModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "ProgressView",
      "bar_style": "success",
      "description": "",
      "description_tooltip": null,
      "layout": "IPY_MODEL_a0025637991f4f539ec3d36b8f7800e9",
      "max": 87319819,
      "min": 0,
      "orientation": "horizontal",
      "style": "IPY_MODEL_3ad88024826049479637996e6cef0f43",
      "value": 87319819
     }
    },
    "d7004b0f0bd640128dffaaf268557d27": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "DescriptionStyleModel",
     "state": {
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "DescriptionStyleModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "StyleView",
      "description_width": ""
     }
    }
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}